/* Copyright (c) 2004-2024 Peigen.info. All rights reserved. */
package info.peigen.hotpot.common.service.base;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson2.annotation.JSONField;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import info.peigen.hotpot.common.core.domain.Domain;
import info.peigen.hotpot.common.core.result.ResultBase;
import info.peigen.hotpot.common.core.result.ResultCode;
import info.peigen.hotpot.common.service.base.exception.BusinessException;
import info.peigen.hotpot.common.service.base.gateway.AbstractGatewayRequest;
import info.peigen.hotpot.common.service.base.gateway.GatewayFacade;
import info.peigen.hotpot.common.service.base.processor.Processor;
import lombok.*;
import lombok.experimental.Accessors;
import lombok.experimental.FieldDefaults;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;

/**
 * <b>(ServiceContext)</b>
 * 所有服务的上下文,可以在Service曾与DomainService层使用
 *
 * @author Peigen
 * @version 1.0.0
 * @since 2019/05/18
 */
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@Accessors(chain = true)
public class ServiceContext<ORDER extends ServiceOrderBase, RESULT extends ResultBase> implements Serializable {
    static final long serialVersionUID = -7996169895294878828L;

    /** 当前数据库时间戳 <code>currentTimestamp</code> */
    Timestamp currentTimestamp;

    /** 请求参数 <code>order</code> */
    ORDER order;

    /** 应答返回 <code>result</code> */
    RESULT result;

    /** 其他可能需要传输的领域对象 <code>domain</code> */
    Domain domain;

    /** 领域服务 */
    DomainService domainService;
    /** 在开启Mock的情况下需要Mock掉的服务可以放到这里 */
    DomainService domainMockService;

    /** 处理器集合 */
    @JSONField(serialize = false)
    @Builder.Default
    List<Processor> processors = Lists.newArrayList();

    /** Service层的Facade,可以认为是依赖的其他Service */
    ServiceFacade serviceFacade;
    /** 在开启Mock的情况下需要Mock掉的服务可以放到这里 */
    ServiceFacade mockServiceFacade;

    /** Gateway层的Facade,可以认为是依赖的网关 */
    GatewayFacade gatewayFacade;
    /** 在开启Mock的情况下需要Mock掉的网关服务可以放到这里 */
    GatewayFacade gatewayMockFacade;

    String channelCode;

    /** 用于传递Request */
    AbstractGatewayRequest request;

    /** 临时用于传递entity */
    Object object;

    /** 扩展参数 */
    @Builder.Default
    Map<String, Object> extend = Maps.newHashMap();

    @Builder.Default
    @JSONField(serialize = false, deserialize = false)
    StopWatch watch = new StopWatch();

    public ServiceContext(ORDER order, RESULT result) {
        this.order = order;
        this.result = result;
    }

    public ServiceContext(ORDER order, RESULT result, ServiceFacade serviceFacade) {
        this.order = order;
        this.result = result;
        this.serviceFacade = serviceFacade;
    }

    public ServiceContext(ORDER order, RESULT result, DomainService domainService) {
        this.order = order;
        this.result = result;
        this.domainService = domainService;
    }

    public ServiceContext(ORDER order, RESULT result, GatewayFacade gatewayFacade) {
        this.order = order;
        this.result = result;
        this.gatewayFacade = gatewayFacade;
    }

    public void addProcessors(Processor processor) {
        Assert.notNull(processor, () -> new BusinessException(ResultCode.FAILURE, "增加处理器为空"));

        if (CollUtil.isEmpty(processors)) {
            processors = Lists.newArrayList();
        }

        // 增加处理器
        processors.add(processor);

        // 自动排序
        processors.stream().sorted();
    }
}